package simpledb.execution;

import simpledb.storage.Tuple;
import simpledb.storage.TupleIterator;

import java.io.Serializable;

/**
 * Aggregator 是一个接口，表示能够对一组 Tuple 进行聚合计算的组件。
 *
 * 例如：可以用于实现 SQL 中的 COUNT、SUM、AVG、MIN、MAX 等聚合操作。
 * 支持按某个字段进行分组（group by）或不进行分组（NO_GROUPING）。
 */
public interface Aggregator {

    /**
     * 表示不进行任何分组的常量。
     */
    int NO_GROUPING = -1;

    /**
     * 聚合操作的枚举类型，定义了所有支持的聚合函数。
     *
     * 注意：SUM_COUNT 和 SC_AVG 主要在 lab7 分布式聚合中使用，
     * 在之前的实验中不需要实现它们。
     */
    enum Op implements Serializable {
        MIN, MAX, SUM, AVG, COUNT,

        /**
         * 同时计算 SUM 和 COUNT，用于分布式 AVG 的计算（lab7 使用）
         */
        SUM_COUNT,

        /**
         * 对多个 SUM_COUNT 类型的结果求平均值（lab7 使用）
         */
        SC_AVG;

        /**
         * 通过字符串形式的索引获取对应的聚合操作。
         * 命令行工具中可能会用到这个方法。
         *
         * @param s 包含整数索引的字符串
         */
        public static Op getOp(String s) {
            return getOp(Integer.parseInt(s));
        }

        /**
         * 通过整数索引获取对应的聚合操作。
         * 命令行工具中可能会用到这个方法。
         *
         * @param i 整数索引
         */
        public static Op getOp(int i) {
            return values()[i];
        }

        /**
         * 返回聚合操作的字符串表示。
         */
        public String toString() {
            if (this == MIN)
                return "min";
            if (this == MAX)
                return "max";
            if (this == SUM)
                return "sum";
            if (this == SUM_COUNT)
                return "sum_count";
            if (this == AVG)
                return "avg";
            if (this == COUNT)
                return "count";
            if (this == SC_AVG)
                return "sc_avg";
            throw new IllegalStateException("不可能到达此处");
        }
    }

    /**
     * 将一个新的 Tuple 合并进聚合结果中。
     * 如果该 Tuple 所属的分组尚未存在，则创建新的聚合结果。
     *
     * @param tup 包含聚合字段和分组字段的元组
     */
    void mergeTupleIntoGroup(Tuple tup);

    /**
     * 创建一个迭代器，用于遍历所有分组的聚合结果。
     *
     * @return 聚合结果的迭代器
     * @see TupleIterator 可以作为实现的帮助类
     */
    OpIterator iterator();
}
